<template>
    <a-dropdown :popPlacement="props.popPlacement" :useTargetWidth="true" :maxHeight="props.maxHeight" v-model:popShown="state.popShown" :trigger="'none'" ref="popupRef">
        <a-control-group class="a-input-select-multi">
            <a-input-string class="c-w-100" :color="formItemHook.myColor" :size="formItemHook.mySize" :sharp="formItemHook.mySharp" :disabled="formItemHook.myDisabled" :value="displayText" @update:value="methods.onUpdateValue" :placeholder="props.placeholder" :readonly="!props.filterable" :clearable="props.clearable" :isInner="true" @click="state.popShown = true" @clear="methods.input([])" @focus="methods.onFocus" @blur="methods.onBlur"></a-input-string>
            <a-button v-if="attachButtonShown" class="c-f-shrink-0" :color="formItemHook.myColor" :size="formItemHook.mySize" :sharp="formItemHook.mySharp" :disabled="formItemHook.myDisabled" :square="true" ref="btn" @click="state.popShown = !state.popShown"><span class="fa fa-fw fa-angle-down"></span></a-button></a-control-group>

        <template v-slot:pop>
            <a-control-group direction="v" :block="true" class="pop" :class="[
                !formItemHook.mySharp ? `c-round-${formItemHook.mySize}` : '',
                ` c-shadow-${formItemHook.mySize}`,
            ]">
                <a-input-check-box-single v-for="a in filteredItems" :key="props.getTextFunc(a)" :color="formItemHook.myColor" :size="formItemHook.mySize" :sharp="formItemHook.mySharp" :disabled="formItemHook.myDisabled || props.getDisabledFunc(a)" :block="true" :plain="true" :value="methods.isItemSelected(a)" :isInner="true" @update:value="methods.toggleSelectItem(a, $event)" class="c-f-h c-f-between-center c-f-shrink-0">
                    <template v-slot:prepend>
                        <span>{{ props.getTextFunc(a) }}</span>
                    </template>
                </a-input-check-box-single>
            </a-control-group>
        </template>
    </a-dropdown>
</template>

<style lang="scss" scoped>
@import "../scss/vars";

.pop {
    background-color: $defaultBgColor;
}
</style>

<script setup lang="ts">
import AInputString from './AInputString.vue'
import AButton from './AButton.vue'
import AControlGroup from './AControlGroup.vue'
import ADropdown from './ADropdown.vue'
import AInputCheckBoxSingle from './AInputCheckBoxSingle.vue'
import { InputPropsType, PopPlacementType, PopupExposed, Rule_maxLength, Rule_minLength, SelectPropsType } from '@/types'
import { computed, reactive, ref, toRef } from 'vue'
import { useInput } from '@/hooks/useInput'
import { useFormItem } from '@/hooks/useFormItem'
import { useSelect } from '@/hooks/useSelect'

interface PropsType extends InputPropsType<any[] | undefined, Rule_minLength | Rule_maxLength>, SelectPropsType {
    items: any[]
    getTextFunc?: (a: any) => string
    getValueFunc?: (a: any) => any
    popPlacement?: PopPlacementType
    separator?: string
    useShortDisplayText?: boolean
    clearable?: boolean
    maxHeight?: number
    placeholder?: string
    attachButtonShown?: boolean
    filterable?: boolean
}
const props = withDefaults(defineProps<PropsType>(), {
    value: undefined,
    color: undefined,
    disabled: undefined,
    size: undefined,
    sharp: undefined,
    rules: () => [],
    isInner: false,
    getDisabledFunc: (a: any) => a.disabled,
    items: () => [],
    getTextFunc: (a: any) => a.text,
    getValueFunc: (a: any) => a.value,
    popPlacement: 'bottom',
    separator: ' ',
    useShortDisplayText: false,
    clearable: true,
    maxHeight: undefined,
    placeholder: undefined,
    attachButtonShown: true,
})

interface StateType {
    popShown: boolean
    inputText: string
    focused: boolean
}
const state = reactive<StateType>({
    popShown: false,
    inputText: '',
    focused: false,
})

const displayText = computed(() => {
    if (props.filterable && state.focused) {
        return state.inputText
    }
    let selectedItems = props.items.filter(a => valueSet.value.has(props.getValueFunc(a)))
    if (selectedItems.length === 0) {
        return ''
    }
    if (props.useShortDisplayText) {
        return props.getTextFunc(selectedItems[0]) + (selectedItems.length > 1 ? `（等${selectedItems.length}项）` : '')
    } else {
        return selectedItems.map(a => props.getTextFunc(a)).join(props.separator)
    }
})
const filteredItems = computed(() => {
    if (!props.filterable) {
        return props.items
    }
    if (!state.inputText) {
        return props.items
    }
    return props.items.filter(a => props.getTextFunc(a).includes(state.inputText))
})
const valueSet = computed(() => {
    return new Set(props.value)
})
const popupRef = ref<PopupExposed>()

const emit = defineEmits<{
    (e: 'update:value', value?: any[]): void
    (e: 'focus'): void
    (e: 'blur'): void
    (e: 'filter', value?: string): void
}>()
useInput(props)
const formItemHook = useFormItem(props)
useSelect(props, popupRef, toRef(props.items))

const methods = {
    input(val?: any[]) {
        emit('update:value', val)
    },
    toggleSelectItem(item: any, selected: boolean) {
        let itemValue = props.getValueFunc(item)
        if (selected) {
            methods.input([...(props.value ?? []), itemValue])
        } else {
            methods.input((props.value ?? []).filter(a => a !== itemValue))
        }
    },
    isItemSelected(item: any) {
        let itemValue = props.getValueFunc(item)
        return valueSet.value.has(itemValue)
    },
    onUpdateValue(val?: string) {
        state.inputText = val ?? ''
        emit('filter', state.inputText)
    },
    onFocus() {
        emit('focus')
        state.focused = true
        state.inputText = ''
    },
    onBlur() {
        emit('blur')
        state.focused = false
    },
}
</script>